// Include
#include "CWinDevice.h"
#include "WindowsHelpers.h"		// Windows helper functions

#include <iostream>				// C++ I/O stream library
#include <SDL/SDL_opengl.h>		// SDL OpenGL implementation
#include <GL/glu.h>				// OpenGL utility header

using namespace std;

namespace EraAstral
{
	namespace graphics
	{
		// Linux graphics device constructor
		WinDevice::WinDevice(core::Logger *logger)
			: IDevice(logger)
		{
			// Set null pointers
			m_screen = NULL;
			
			// Set logger class pointer
			m_logger = logger;
		
			// Initialize SDL - Only initializes video sub system
			if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0)
			{
				// Error occured
				cout << "Error during SDL initialization." << endl;
			}
			else
			{
				// SDL initialized successfully
				
				// Default bits per pixel value
				int bpp = WIN_DEFAULT_BPP;
				// Video information
				const SDL_VideoInfo *vidInfo = NULL;
				// Get video information
				vidInfo = SDL_GetVideoInfo();
				if (vidInfo != NULL)
					bpp = vidInfo->vfmt->BitsPerPixel;
				
				// Set SDL/OpenGL attributes
				IDevice::SetSDLGLAttributes();

				// Screen surface creation flags
				int flags = SDL_OPENGL | SDL_RESIZABLE;
				
				m_backBufferWidth = WIN_DEFAULT_WIDTH;
				m_backBufferHeight = WIN_DEFAULT_HEIGHT;
				m_winWidth = WIN_DEFAULT_WIDTH;
				m_winHeight = WIN_DEFAULT_HEIGHT;
				
				// Create screen surface
				m_screen = SDL_SetVideoMode(WIN_DEFAULT_WIDTH, WIN_DEFAULT_HEIGHT, bpp, flags);
				if (m_screen == NULL)
				{
					// Screen surface not created
					cout << "Error creating screen surface." << endl;
				}
				else
				{
					// Screen surface successfully created
					// Set window caption
					SDL_WM_SetCaption("Era Astral", NULL);
					// Initialize OpenGL
					IDevice::InitOpenGL();
					// Fit OpenGL viewport to new window
					IDevice::ResizeGLView(WIN_DEFAULT_WIDTH, WIN_DEFAULT_HEIGHT);
				}
			}
		}
		
		// Linux graphics device destructor
		WinDevice::~WinDevice()
		{
			// Quit SDL
			if (SDL_WasInit(SDL_INIT_VIDEO))
				SDL_Quit();
		}
		
		// Begins a new frame
		void WinDevice::BeginFrame()
		{
			// Clear back buffer, depth buffer and stencil buffer
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
		}
		
		// Ends the frame and presents to the screen
		void WinDevice::EndFrame()
		{
			// Swap buffers
			SDL_GL_SwapBuffers();
		}
		
		// Sets a perspective field of view
		void WinDevice::SetPerspective()
		{
			// Projection matrix
			glMatrixMode(GL_PROJECTION);
			// Load identity matrix
			glLoadIdentity();
			// Set perspective
			gluPerspective(45.0f, (float)m_winWidth / (float)m_winHeight, 0.1f, 1000.0f);
			
			// Go to model view matrix
			glMatrixMode(GL_MODELVIEW);
		}
		
		// Sets a orthographic field of view
		void WinDevice::SetOrtho()
		{
			// Projection matrix
			glMatrixMode(GL_PROJECTION);
			// Load identity matrix
			glLoadIdentity();
			// Set orthographic view
			glOrtho(0, m_winWidth, 0, m_winHeight, -1, 1);
			
			// Go to model view matrix
			glMatrixMode(GL_MODELVIEW);
		}
		
		// Changes game resolution
		void WinDevice::ChangeResolution(unsigned int width, unsigned int height)
		{
			// Validate parameters
			if (width == 0)
				width = WIN_DEFAULT_WIDTH;
			if (height == 0)
				height = WIN_DEFAULT_HEIGHT;

			// Get old bits per pixel value
			Uint8 bpp = m_screen->format->BitsPerPixel;
			int flags = m_screen->flags;

			m_backBufferWidth = width;
			m_backBufferHeight = height;

			// Create new screen surface
			m_screen = SDL_SetVideoMode(width, height, bpp, flags);
		}

		// Toggles full screen mode
		void WinDevice::ToggleFullScreen()
		{
			// Use SDL window management function
			SDL_WM_ToggleFullScreen(m_screen);
		}
		
		// Changes the caption of the window
		void WinDevice::SetWindowCaption(const char *caption)
		{
			// Use SDL window management function
			SDL_WM_SetCaption(caption, NULL);
		}
		
		// Toggles grab input mode
		void WinDevice::ToggleGrabInput()
		{
			// Check current grab mode
			if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF)
				SDL_WM_GrabInput(SDL_GRAB_ON);
			else
				SDL_WM_GrabInput(SDL_GRAB_OFF);
		}
	}
}
